#include "stdafx.h"
#include "os_file.h"
#include "Vector.h"

namespace OperatingSystem
{
	File::File()
	{
		myFlags = 0xF;
	}

	File::File(const std::string aFileName, FileFlagsType aSetOfFlags)
	{
		myFlags = aSetOfFlags;
		Open(aFileName, aSetOfFlags);
	}

	File::~File()
	{
		Close();
	}

	bool File::Open(const std::string aFileName, FileFlagsType aSetOfFlags)
	{
		myFileName = aFileName;

		bool opened = false;
		myFlags = aSetOfFlags;
		int flags = 0;
		if(myFlags.test(T_READ))
		{
			flags |= std::ios::in;
			opened = true;
		}
		if(myFlags.test(T_WRITE))
		{
			flags |= std::ios::out;
			opened = true;
		}
		if(myFlags.test(T_APPEND))
		{
			myFlags.set(T_WRITE);
			flags |= std::ios::app;
			opened = true;
		}
		if(opened == false)
		{
			flags |= std::ios::in;
			myFlags.set(T_READ);
		}
		if(myFlags.test(T_BINARY))
		{
			flags |= std::ios::binary;
		}
		if(myFile.is_open())
		{
			myFile.close();
			myFile.clear();
		}
		myFile.clear();
		myFile.open(aFileName.c_str(), static_cast<std::ios::openmode>(flags));

		if(myFile.good())
		{
			return true;
		}

		return false;
	}

	bool File::Close()
	{
		if(myFile.is_open())
		{
			myFile.close();
			myFile.clear();
			return true;
		}
		return false;
	}

	bool File::FlushToDisk()
	{
		if(myFile.is_open() && myFlags.test(T_WRITE))
		{
			myFile.flush();
			return true;
		}
		return false;
	}

	unsigned int File::GetFileSize()
	{
		if (myFile.is_open()==false)
		{
			return 0;
		}
		std::fstream::pos_type cur_pos = myFile.tellg();
		myFile.seekg(0, std::ios_base::beg);
		std::fstream::pos_type begin_pos = myFile.tellg();
		myFile.seekg(0, std::ios_base::end);
		std::fstream::pos_type end_pos = myFile.tellg();
		myFile.seekg(0, cur_pos);
		return (end_pos - begin_pos);
	}

	bool File::GoToNewLine()
	{
		char c = '\0';
		if(myFile.is_open())
		{
			if(myFlags.test(T_READ))
			{
				while (myFile.eof() == false)
				{
					myFile.read(&c, 1);
					if (c == '\n')
					{
						myFile.unget();
						return true;
					}
				}
				return true;
			}
		}
		return false;
	}

	bool File::ReadData(void *someData, int aSizeToRead)
	{
		if(myFile.is_open() && myFlags.test(T_READ))
		{
			myFile.read(static_cast<char *>(someData), aSizeToRead);
			return myFile.good();
		}
		return false;
	}

	bool File::ReadDouble(double &aDouble)
	{
		if(myFile.is_open() && myFlags.test(T_READ))
		{
			if(myFlags.test(T_BINARY))
			{
				ReadData(&aDouble, sizeof(double));
			}
			else
			{
				char p = '\0';
				char c = '\0';
				while (myFile.eof() == false)
				{
					myFile >> c;
					if ((c >= '0') && (c <= '9'))
					{
						if ((p == '-') || (p == '.'))
						{
							myFile.unget();
						}
						myFile.unget();
						break;
					}
					p = c;
				}
				myFile >> aDouble;
			}
			if(myFile.good())
			{
				return true;
			}
		}
		return false;
	}

	bool File::ReadFloat(float &aFloat)
	{
		if(myFile.is_open() && myFlags.test(T_READ))
		{
			if(myFlags.test(T_BINARY))
			{
				ReadData(&aFloat, sizeof(float));
			}
			else
			{
				char p = '\0';
				char c = '\0';
				while (myFile.eof() == false)
				{
					myFile >> c;
					if ((c >= '0') && (c <= '9'))
					{
						if ((p == '-') || (p == '.'))
						{
							myFile.unget();
						}
						myFile.unget();
						break;
					}
					p = c;
				}
				myFile >> aFloat;
			}
			if(myFile.good())
			{
				return true;
			}
		}
		return false;
	}

	bool File::ReadInt(int &anInteger)
	{
		if(myFile.is_open() && myFlags.test(T_READ))
		{
			if(myFlags.test(T_BINARY))
			{
				ReadData(&anInteger, sizeof(int));
			}
			else
			{
				char p = '\0';
				char c = '\0';
				while (myFile.eof() == false)
				{
					myFile >> c;
					if ((c >= '0') && (c <= '9'))
					{
						if (p == '-')
						{
							myFile.unget();
						}
						myFile.unget();
						break;
					}
					p = c;
				}
				myFile >> anInteger;
			}
			if(myFile.good())
			{
				return true;
			}
		}
		return false;
	}

	bool File::ReadInt(unsigned int &anInteger)
	{
		if(myFile.is_open() && myFlags.test(T_READ))
		{
			if(myFlags.test(T_BINARY))
			{
				ReadData(&anInteger, sizeof(int));
			}
			else
			{
				char p = '\0';
				char c = '\0';
				while (myFile.eof() == false)
				{
					myFile >> c;
					if ((c >= '0') && (c <= '9'))
					{
						if (p == '-')
						{
							myFile.unget();
						}
						myFile.unget();
						break;
					}
					p = c;
				}
				myFile >> anInteger;
			}
			if(myFile.good())
			{
				return true;
			}
		}
		return false;
	}

	bool File::ReadWord(std::string &aString)
	{
		if(myFile.is_open() && myFlags.test(T_READ))
		{
			myFile >> aString;
			return myFile.good();
		}
		return false;
	}

	bool File::ReadString(std::string &aString)
	{
		if(myFile.is_open() && myFlags.test(T_READ))
		{
			char p = '\0';
			char c = '\0';
			aString = "";
			while (myFile.eof() == false)
			{
				myFile >> c;
				if (c == '"')
				{
					if (p != '\\')
					{
						break;
					}
				}
				p = c;
			}
			while (myFile.eof() == false)
			{
				myFile.read(&c, 1);
				if (c == '"')
				{
					if (p != '\\')
					{
						//myFile.unget();
						break;
					}
				}
				aString += c;
				p = c;
			}
			return myFile.good();
		}
		return false;
	}

	bool File::ReadBool(bool& aFlag)
	{
		int flag = 0;
		bool returnFlag = ReadInt(flag);
		aFlag = flag != 0;
		return returnFlag;
	}

	bool File::WriteData(void *someData, int aSizeToWrite)
	{
		if(myFile.is_open() && myFlags.test(T_WRITE))
		{
			myFile.write(static_cast<char *>(someData), aSizeToWrite);
			return myFile.good();
		}
		return false;
	}

	bool File::WriteDouble(double &aDouble)
	{
		if(myFile.is_open() && myFlags.test(T_WRITE))
		{
			if(myFlags.test(T_BINARY))
			{
				WriteData(&aDouble, sizeof(double));
			}
			else
			{
				myFile << aDouble;
			}
			return myFile.good();
		}
		return false;
	}

	bool File::WriteFloat(float &aFloat)
	{
		if(myFile.is_open() && myFlags.test(T_WRITE))
		{
			if(myFlags.test(T_BINARY))
			{
				WriteData(&aFloat, sizeof(float));
			}
			else
			{
				myFile << aFloat;
			}
			return myFile.good();
		}
		return false;
	}

	bool File::WriteInt(int &anInteger)
	{
		if(myFile.is_open() && myFlags.test(T_WRITE))
		{
			if(myFlags.test(T_BINARY))
			{
				WriteData(&anInteger, sizeof(int));
			}
			else
			{
				myFile << anInteger;
			}
			return myFile.good();
		}
		return false;
	}

	bool File::WriteString(std::string aString)
	{
		if(myFile.is_open() && myFlags.test(T_WRITE))
		{
			if(myFlags.test(T_BINARY))
			{
				WriteData(const_cast<char *>(aString.c_str()), sizeof(char) * aString.size());
			}
			else
			{
				myFile << aString;
			}
			return myFile.good();
		}
		return false;
	}

	bool File::WriteBool(bool& aFlag)
	{
		int flag = static_cast<int>(aFlag);
		return WriteInt(flag);
	}

	bool File::Clear()
	{
		bool state = myFile.good();
		myFile.clear();
		return state;
	}

	bool File::IsOpen() const
	{
		return myFile.is_open();
	}

	bool File::Eof() const
	{
		return myFile.eof();
	}

	const std::string& File::GetFileName()
	{
		return myFileName;
	}

};
